package com.fili.editor;

import java.awt.*;
import java.awt.geom.Point2D;
import java.util.ArrayList;

/**
 * Created by IntelliJ IDEA.
 * User: Fili
 * Date: Mar 11, 2007
 * Time: 1:24:30 PM
 */
public class BezierCurve
{
    private Point[] points;
    private int selected;


    public int getSelected()
    {
        return selected;
    }

    public void setSelected(int selected)
    {
        this.selected = selected;
    }


    public Point[] getPoints()
    {
        return points;
    }

    public void setPoints(Point[] points)
    {
        this.points = points;
    }

    public BezierCurve()
    {
        points = new Point[4];
    }

    private void drawPoint(Graphics g, int p)
    {
        if (p == selected)
            g.fillRect(points[p].x - 2, points[p].y - 2, 5, 5);
        else
            g.drawRect(points[p].x - 2, points[p].y - 2, 4, 4);

    }

    public Point2D.Double[] getCurvePoints(double step)
    {
        ArrayList<Point2D> bp = new ArrayList<Point2D>();

        for (double u = 0; u <= 1; u += step)
        {
            double u3 = u * u * u;
            double u2 = 3 * u * u * (1 - u);
            double u1 = 3 * u * (1 - u) * (1 - u);
            double u0 = (1 - u) * (1 - u) * (1 - u);

            Point2D p = new Point2D.Double();

            double x = points[0].x * u0 + points[1].x * u1 + points[2].x * u2 + points[3].x * u3;
            double y = points[0].y * u0 + points[1].y * u1 + points[2].y * u2 + points[3].y * u3;

            p.setLocation(x, y);
            bp.add(p);
        }

        Point2D.Double[] pts = new Point2D.Double[bp.size()];
        return bp.toArray(pts);
    }

    private void renderCurve(Graphics2D g, Point2D[] pts)
    {
        for (int i = 0; i < pts.length - 1; i++)
        {
            g.drawLine((int) pts[i].getX(), (int) pts[i].getY(), (int) pts[i + 1].getX(), (int) pts[i + 1].getY());
        }
    }

    public void render(Graphics2D g)
    {
        Point2D.Double[] pts = getCurvePoints(0.1);
        g.setColor(Color.yellow);
        g.setStroke(new BasicStroke(15,BasicStroke.CAP_ROUND, BasicStroke.CAP_ROUND));
        renderCurve(g,pts);

        g.setStroke(new BasicStroke(1));
        g.setColor(Color.green);
        g.drawLine(points[0].x, points[0].y, points[1].x, points[1].y);
        g.drawLine(points[2].x, points[2].y, points[3].x, points[3].y);
        g.setColor(Color.blue);
        for (int i = 0; i < 4; i++)
            drawPoint(g, i);

        
        g.setColor(Color.red);
        renderCurve(g,pts);

    }

    public double dist(int x, int y)
    {
        double min = dist(0, x, y);
        for (int i = 1; i < 4; i++)
        {
            double m = dist(i, x, y);
            if (m < min)
                min = m;
        }
        return min;
    }

    public double dist(int p, int x, int y)
    {
        int dx = x - points[p].x;
        int dy = y - points[p].y;

        return Math.sqrt(dx * dx + dy * dy);
    }

    public void select(int x, int y)
    {
        double min = dist(0, x, y);
        selected = 0;
        for (int i = 1; i < 4; i++)
        {
            double m = dist(i, x, y);
            if (m < min)
            {
                min = m;
                selected = i;
            }
        }
    }

    public void drag(int x, int y)
    {
        if (selected >= 0)
        {
            points[selected].x = x;
            points[selected].y = y;
        }
    }
}
